﻿using BaseInfo;
using Bridge.Shared.Enums.Wms;
using Bridge.Shared.Models;
using Microsoft.EntityFrameworkCore;
using NPOI.OpenXmlFormats.Spreadsheet;
using Stock.Input;
using Stock.Output;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Specifications;
using Vouchers;
using Vouchers.InStockVouchers;

namespace Stock
{
    public class StockService : ApplicationService, IStockService
    {
        private readonly IRepository<FlowStock, Guid> _flowStockRepository;
        private readonly IRepository<LockStock, Guid> _lockStockRepository;
        private readonly IRepository<ProductTrackStock, Guid> _productTrackStockRepository;
        private readonly IVoucherStockServiceFactory _voucherStockServiceFactory;
        public StockService(IRepository<FlowStock, Guid> flowStockRepository,
                            IRepository<LockStock, Guid> lockStockRepository,
                            IRepository<ProductTrackStock, Guid> productTrackStockRepository,
                            IVoucherStockServiceFactory voucherStockServiceFactory) {
        _flowStockRepository = flowStockRepository;
            _lockStockRepository = lockStockRepository;
            _productTrackStockRepository = productTrackStockRepository;
            _voucherStockServiceFactory = voucherStockServiceFactory;
        }
       public async Task<ResponseResult> InStock(GetStockInput input)
        {
           //1. 组装要入库的数据
            var inStockList = new List<InStockOutput>();

            IInVoucherStockService voucherStockService =  _voucherStockServiceFactory.CreateInStock(input.VoucherType);
            inStockList = await voucherStockService.GetInStock(input);
            
           var deptIds = inStockList.Select(a=>a.DeptId).ToList();
            var productCosdes = inStockList.Select(a => a.ProductCode).ToList();
            var trackCodes = inStockList.Select(a => a.TrackCode).ToList();

            //2. 查询存在的库存
            var stocks = await (await _productTrackStockRepository.GetQueryableAsync())
                         .Where(a => deptIds.Contains(a.DeptId))
                         .Where(a => productCosdes.Contains(a.ProductCode))
                         .Where(a => trackCodes.Contains(a.TrackCode))
                         .ToListAsync();

            //3. 查询修改和新增的数据
            List<ProductTrackStock> insertStockList = new();
            List<ProductTrackStock> updateStcokList = new();
            List<FlowStock> flowStockList = new();

            foreach (var inStock in inStockList) {
                decimal BeforeStockCount = 0;
                decimal AfterStockCount = 0;
                var stock = stocks.Where(a => a.DeptId == inStock.DeptId)
                                       .Where(a => a.ProductCode == inStock.ProductCode)
                                       .Where(a => a.TrackCode == inStock.TrackCode)
                                       .Where(a => a.Price == inStock.Price)
                                       .Where(a => a.Specification == inStock.Specification)
                                       .Where(a => a.ExpiryDate == inStock.ExpiryDate)
                                       .Where(a => a.ProductBatch == inStock.ProductBatch)
                                       .FirstOrDefault();
                if(stock != null)
                {
                    AfterStockCount = stock.StockCount + inStock.InStockCount;
                    stock.StockCount += inStock.InStockCount;
                    updateStcokList.Add(stock);
                }
                else
                {

                    AfterStockCount = stock.StockCount;

                    //排次库存
                    ProductTrackStock productTrackStock = new ProductTrackStock(GuidGenerator.Create())
                    {
                        DeptId = inStock.DeptId,
                        DeptName = inStock.DeptName,
                        ProductCode = inStock.ProductCode,
                        ProductName = inStock.ProductName,
                        ProductBatch = inStock.ProductBatch,
                        ProductClassName = inStock.ProductClassName,
                        ProductDate = inStock.ProductDate,
                        ExpiryDate = inStock.ExpiryDate,
                        StockType= StockTypeEnum.Quantity,
                        StockCount=inStock.InStockCount,
                        Price=stock.Price,
                        ProducttClassId=inStock.ProductClassId,
                        ManufactureName=inStock.ManufactureName,
                        ManufactureId=inStock.ManufactureId,
                        TrackCode=inStock.TrackCode,
                        InStockVoucherCode = inStock.VoucherCode,
                        InStockCount= inStock.InStockCount,
                        Specification = inStock.Specification,
                        SupplierId = inStock.SupplierId,
                        SupplierName = inStock.SupplierName,

                    };


                    insertStockList.Add(productTrackStock);
                }

                //流水
                FlowStock flowStock = new FlowStock(GuidGenerator.Create())
                {
                    VoucherCode = inStock.VoucherCode,
                    RealationId = inStock.RealationId,
                    DeptId = inStock.DeptId,
                    ProductCode=inStock.ProductCode,
                    ProductName = inStock.ProductName,
                    ProductBatch = inStock.ProductBatch,
                    OutInCount=inStock.InStockCount,
                    OutInPrice=inStock.Price,
                    ProductClassName=inStock.ProductClassName,
                    ProductDate=inStock.ProductDate,
                    ExpiryDate=inStock.ExpiryDate,
                    TrackCode=inStock.TrackCode,
                    InStockVoucherCode=inStock.VoucherCode,
                    OutInFlag = OutInFlagEnum.InStock,
                    OutInType = inStock.OutInType,
                    SupplierId=stock.SupplierId,
                    StockId=stock.Id,
                    BeforeStockCount=BeforeStockCount,
                    AfterStockCount= AfterStockCount,
                    OutInTime=DateTime.Now,

                };

                flowStockList.Add(flowStock);

            }

            //4. 更新库存表
           await  _productTrackStockRepository.InsertManyAsync(insertStockList);
           await _productTrackStockRepository.UpdateManyAsync(updateStcokList);
           await _flowStockRepository.InsertManyAsync(flowStockList);

            return ResponseResult.Success("ok");

        }


       

       public async Task<ResponseResult> OutStock(GetStockInput input)
        {
            //1. 组装要出库的数据
            var outStockList = new List<OutStockOutput>();

            IOutVoucherStockService voucherStockService = _voucherStockServiceFactory.CreateOutStock(input.VoucherType);
            outStockList = await voucherStockService.GetOutStock(input);

            var deptIds = outStockList.Select(a => a.DeptId).ToList();
            var productCosdes = outStockList.Select(a => a.ProductCode).ToList();
            var trackCodes = outStockList.Select(a => a.TrackCode).ToList();

            //2. 查询存在的库存
            var stocks = await(await _productTrackStockRepository.GetQueryableAsync())
                         .Where(a => deptIds.Contains(a.DeptId))
                         .Where(a => productCosdes.Contains(a.ProductCode))
                         .Where(a => trackCodes.Contains(a.TrackCode))
                         .ToListAsync();
            if (stocks.Any())
            {
                return ResponseResult.Fail("库存不存在!");
            }
            var lockStocks = (await _lockStockRepository.GetQueryableAsync()).Where(a=>stocks.Select(a=>a.Id).ToList().Contains(a.StockId)).ToList();

            //3. 查询修改和新增的数据
            List<ProductTrackStock> insertStockList = new();
            List<ProductTrackStock> updateStcokList = new();
            List<FlowStock> flowStockList = new();
            foreach (var outStock in outStockList)
            {
                decimal BeforeStockCount = 0;
                decimal AfterStockCount = 0;
                var stock = stocks.Where(a => a.DeptId == outStock.DeptId)
                                       .Where(a => a.ProductCode == outStock.ProductCode)
                                       .Where(a => a.TrackCode == outStock.TrackCode)
                                       .Where(a => a.Price == outStock.Price)
                                       .Where(a => a.Specification == outStock.Specification)
                                       .Where(a => a.ExpiryDate == outStock.ExpiryDate)
                                       .Where(a => a.ProductBatch == outStock.ProductBatch)
                                       .FirstOrDefault();
                if (stock == null )
                {
                    return ResponseResult.Fail($"库存不存在,科室【{outStock.DeptName}】产品【{outStock.ProductCode}】追溯码【{outStock.TrackCode}】");
                }
                var lockStockCount = lockStocks.Where(a=>a.StockId == stock.Id).Sum(a=>a.LockCount);
                if(stock.InStockCount - lockStockCount < outStock.Count)
                {
                    return ResponseResult.Fail($"库存不足,出库数量【{outStock.Count}】，库存数量【{stock.InStockCount}】，锁定库存数【{lockStockCount}】,科室【{outStock.DeptName}】产品【{outStock.ProductCode}】追溯码【{outStock.TrackCode}】");
                }
                
                
                    BeforeStockCount=stock.InStockCount;
                    AfterStockCount = stock.InStockCount-outStock.Count;
                    stock.StockCount -= outStock.Count;
                    updateStcokList.Add(stock);

                    //流水
                    FlowStock flowStock = new FlowStock(GuidGenerator.Create())
                    {
                        VoucherCode = outStock.VoucherCode,
                        RealationId = outStock.RealationId,
                        DeptId = outStock.DeptId,
                        ProductCode = outStock.ProductCode,
                        ProductName = outStock.ProductName,
                        ProductBatch = outStock.ProductBatch,
                        OutInCount = outStock.Count,
                        OutInPrice = outStock.Price,
                        ProductClassName = outStock.ProductClassName,
                        ProductDate = outStock.ProductDate,
                        ExpiryDate = outStock.ExpiryDate,
                        TrackCode = outStock.TrackCode,
                        InStockVoucherCode = outStock.VoucherCode,
                        OutInFlag = OutInFlagEnum.InStock,
                        OutInType = outStock.OutInType,
                        SupplierId = stock.SupplierId,
                        StockId = stock.Id,
                        BeforeStockCount = BeforeStockCount,
                        AfterStockCount = AfterStockCount,
                        OutInTime = DateTime.Now,

                    };

                    flowStockList.Add(flowStock);
                

            }

            //4. 更新库存表
            await _productTrackStockRepository.UpdateManyAsync(updateStcokList);

            await _flowStockRepository.InsertManyAsync(flowStockList);

            return ResponseResult.Success("ok");
        }
       public async Task<ResponseResult> AllotStock(GetStockInput input)
        {
            //1. 组装要调拨的数据
            var allotStockList = new List<AllotStockOutput>();

            IAllotVoucherStockService voucherStockService = _voucherStockServiceFactory.CreateAllotStock(input.VoucherType);
            allotStockList = await voucherStockService.GetAllotStock(input);

            var deptIds = new List<Guid>();
            var inDeptIds = allotStockList.Select(a => a.InDeptId).ToList();
            var outDeptIds = allotStockList.Select(a=>a.OutDeptId).ToList();
            deptIds.AddRange(inDeptIds);
            deptIds.AddRange(outDeptIds);

            var productCosdes = allotStockList.Select(a => a.ProductCode).ToList();
            var trackCodes = allotStockList.Select(a => a.TrackCode).ToList();

            //2. 查询存在的库存
            var stocks = await(await _productTrackStockRepository.GetQueryableAsync())
                         .Where(a => deptIds.Contains(a.DeptId))
                         .Where(a => productCosdes.Contains(a.ProductCode))
                         .Where(a => trackCodes.Contains(a.TrackCode))
                         .ToListAsync();
            if (stocks.Any())
            {
                return ResponseResult.Fail("库存不存在!");
            }
            var lockStocks = (await _lockStockRepository.GetQueryableAsync()).Where(a => stocks.Select(a => a.Id).ToList().Contains(a.StockId)).ToList();

            //3. 查询修改和新增的数据
            List<ProductTrackStock> insertStockList = new();
            List<ProductTrackStock> updateStcokList = new();
            List<FlowStock> flowStockList = new();
            foreach (var allotStock in allotStockList)
            {
                

                decimal outBeforeStockCount = 0;
                decimal outAfterStockCount = 0;
                decimal inBeforeStockCount = 0;
                decimal inAfterStockCount = 0;
                var stock = stocks.Where(a => a.DeptId == allotStock.OutDeptId)
                                       .Where(a => a.ProductCode == allotStock.ProductCode)
                                       .Where(a => a.TrackCode == allotStock.TrackCode)
                                       .Where(a => a.Price == allotStock.Price)
                                       .Where(a => a.Specification == allotStock.Specification)
                                       .Where(a => a.ExpiryDate == allotStock.ExpiryDate)
                                       .Where(a => a.ProductBatch == allotStock.ProductBatch)
                                       .FirstOrDefault();
                if (stock == null || stock.InStockCount < allotStock.AllotStockCount)
                {
                    return ResponseResult.Fail($"库存不存在,科室【{allotStock.OutDeptName}】产品【{allotStock.ProductCode}】追溯码【{allotStock.TrackCode}】");
                }
                var lockStockCount = lockStocks.Where(a => a.StockId == stock.Id).Sum(a => a.LockCount);
                if (stock.InStockCount - lockStockCount < allotStock.AllotStockCount)
                {
                    return ResponseResult.Fail($"库存不足,出库数量【{allotStock.AllotStockCount}】，库存数量【{stock.InStockCount}】，锁定库存数【{lockStockCount}】,科室【{allotStock.OutDeptName}】产品【{allotStock.ProductCode}】追溯码【{allotStock.TrackCode}】");
                }

                #region 处理要出库的科室数据

                outBeforeStockCount = stock.InStockCount;
                    outAfterStockCount = stock.InStockCount - allotStock.AllotStockCount;
                    stock.StockCount -= allotStock.AllotStockCount;
                    updateStcokList.Add(stock);

                    //出流水
                    FlowStock outFlowStock = new FlowStock(GuidGenerator.Create())
                    {
                        VoucherCode = allotStock.VoucherCode,
                        RealationId = allotStock.RealationId,
                        DeptId = allotStock.OutDeptId,
                        ProductCode = allotStock.ProductCode,
                        ProductName = allotStock.ProductName,
                        ProductBatch = allotStock.ProductBatch,
                        OutInCount = allotStock.AllotStockCount,
                        OutInPrice = allotStock.Price,
                        ProductClassName = allotStock.ProductClassName,
                        ProductDate = allotStock.ProductDate,
                        ExpiryDate = allotStock.ExpiryDate,
                        TrackCode = allotStock.TrackCode,
                        InStockVoucherCode = allotStock.VoucherCode,
                        OutInFlag = OutInFlagEnum.AllotStock,
                        OutInType = allotStock.OutInType,
                        SupplierId = stock.SupplierId,
                        StockId = stock.Id,
                        BeforeStockCount = outBeforeStockCount,
                        AfterStockCount = outAfterStockCount,
                        OutInTime = DateTime.Now,

                    };

                    flowStockList.Add(outFlowStock);
                #endregion

                #region 处理要入库的科室数据
                
                outAfterStockCount = allotStock.AllotStockCount;

                ProductTrackStock productTrackStock = new ProductTrackStock(GuidGenerator.Create())
                {
                    DeptId = allotStock.InDeptId,
                    DeptName = allotStock.InDeptName,
                    ProductCode = allotStock.ProductCode,
                    ProductName = allotStock.ProductName,
                    ProductBatch = allotStock.ProductBatch,
                    ProductClassName = allotStock.ProductClassName,
                    ProductDate = allotStock.ProductDate,
                    ExpiryDate = allotStock.ExpiryDate,
                    StockType = StockTypeEnum.Quantity,
                    StockCount = allotStock.AllotStockCount,
                    Price = stock.Price,
                    ProducttClassId = allotStock.ProductClassId,
                    ManufactureName = allotStock.ManufactureName,
                    ManufactureId = allotStock.ManufactureId,
                    TrackCode = allotStock.TrackCode,
                    InStockVoucherCode = allotStock.VoucherCode,
                    InStockCount = allotStock.AllotStockCount,
                    Specification = allotStock.Specification,
                    SupplierId = allotStock.SupplierId,
                    SupplierName = allotStock.SupplierName,

                };


                insertStockList.Add(productTrackStock);
                //出流水
                FlowStock inFlowStock = new FlowStock(GuidGenerator.Create())
                {
                    VoucherCode = allotStock.VoucherCode,
                    RealationId = allotStock.RealationId,
                    DeptId = allotStock.OutDeptId,
                    ProductCode = allotStock.ProductCode,
                    ProductName = allotStock.ProductName,
                    ProductBatch = allotStock.ProductBatch,
                    OutInCount = allotStock.AllotStockCount,
                    OutInPrice = allotStock.Price,
                    ProductClassName = allotStock.ProductClassName,
                    ProductDate = allotStock.ProductDate,
                    ExpiryDate = allotStock.ExpiryDate,
                    TrackCode = allotStock.TrackCode,
                    InStockVoucherCode = allotStock.VoucherCode,
                    OutInFlag = OutInFlagEnum.InStock,
                    OutInType = allotStock.OutInType,
                    SupplierId = stock.SupplierId,
                    StockId = stock.Id,
                    BeforeStockCount = inBeforeStockCount,
                    AfterStockCount = inAfterStockCount,
                    OutInTime = DateTime.Now,

                };

                flowStockList.Add(inFlowStock);

            }

            #endregion

            //4. 更新库存表
            await _productTrackStockRepository.UpdateManyAsync(updateStcokList);
            await _productTrackStockRepository.InsertManyAsync(insertStockList);
            await _flowStockRepository.InsertManyAsync(flowStockList);

            return ResponseResult.Success("ok");
        }
       public async Task<ResponseResult> LockStock(List<LockStockInput> input)
        {
            try
            {
                var deptIds = input.Select(a => a.DeptId).ToList();
                var productCodes = input.Select(a => a.ProductCode).ToList();
                var trackCodes = input.Select(a => a.TrackCode).ToList();
                //1. 查询存在的库存
                var query = await _productTrackStockRepository.GetQueryableAsync();
                var stocks = await query
                             .Where(a => deptIds.Contains(a.DeptId))
                             .Where(a => productCodes.Contains(a.ProductCode))
                             .Where(a => trackCodes.Contains(a.TrackCode))
                             .Where(a => a.StockCount > 0)
                             .ToListAsync();
                if (!stocks.Any())
                {
                    return ResponseResult.Fail("库存不足！");
                }

                var lockStockList = new List<LockStock>();
                foreach (var item in input)
                {
                    var stock = stocks.Where(a => a.DeptId == item.DeptId
                                                                     && a.ProductCode == item.ProductCode
                                                                     && a.ProductBatch == item.ProductBatch
                                                                     && a.Price == item.Price
                                                                     && a.ShelfCode == item.ShelfCode
                                                                     && a.TrackCode == item.TrackCode
                                                                     && a.ExpiryDate == item.ExpiryDate
                                                                     && a.StockType == item.StockType
                                                                     )
                                    .WhereIf(!string.IsNullOrEmpty(item.BarCode), a => a.BarCode == item.BarCode)
                                    .WhereIf(!string.IsNullOrEmpty(item.UdiCode), a => a.UdiCode == item.UdiCode)
                                    .WhereIf(!string.IsNullOrEmpty(item.OnlyBarCode), a => a.OnlyBarCode == item.OnlyBarCode)
                                    .FirstOrDefault();

                    var lockStockInfo = $"部门：{item.DeptName}|产品:{item.ProductCode}|条形码:{item.BarCode ?? ""}|唯一码:{item.OnlyBarCode ?? ""}";
                    if (stock == null)
                    {
                        return ResponseResult.Fail($"未找到批次库存信息,{lockStockInfo}");
                    }

                    decimal AvailableStock = stock.StockCount - lockStockList.Sum(a => a.LockCount);
                    if (item.LockCount > AvailableStock)
                    {

                        return ResponseResult.Fail($"库存不足无法锁定,{lockStockInfo}");

                    }

                    var lockstock = new LockStock(GuidGenerator.Create())
                    {
                        DeptId = item.DeptId,
                        ProductCode = item.ProductCode,
                        VoucherCode = item.VoucherCode,
                        StockId = stock.Id,
                        LockCount = item.LockCount
                    };


                    lockStockList.Add(lockstock);


                }

                await _lockStockRepository.InsertManyAsync(lockStockList);

                return ResponseResult.Success("锁定库存成功!");
            }
            catch (Exception ex)
            {
                return ResponseResult.Fail($"锁定库存失败，原因：{ex.Message}!");
            }
        }
       public async Task<ResponseResult> UnLockStock(List<UnLockStockInput> input)
        {
            try
            {
                var voucherList = input.Select(a => a.VoucherCode).ToList();
                var stockIdList = input.Select(a => a.StockId).ToList();
                var lockStockList = (await _lockStockRepository.GetQueryableAsync()).Where(a => voucherList.Contains(a.VoucherCode))
                                                                                   .Where(a => stockIdList.Contains(a.StockId)).ToList();
                if (lockStockList.Count > 0)
                {
                    await _lockStockRepository.HardDeleteAsync(lockStockList);
                }
                return ResponseResult.Success("解锁库存成功！");
            }
            catch (Exception ex)
            {
                return ResponseResult.Success($"解锁库存失败，原因{ex.Message}");
            }
        }
    }
}
